/**
 * 
 */
package com.qianhai.manage.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.support.ApplicationObjectSupport;

import com.qianhai.manage.service.IDefaultService;
import com.qianhai.manage.util.KeyUtil;
import com.qianhai.manage.util.StringUtil;
import com.qianhai.manage.vo.ValueObject;

/**
 * @author Administrator
 *
 */
public class DefaultServiceImpl extends ApplicationObjectSupport implements 
		IDefaultService {
	
	public static final int FREQUENCY_SIZE = 1000;

	private DataSource dataSource;

	private SqlSessionTemplate sqlSessionTemplate;

	private KeyUtil keyGenerator;

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	
	/*
	* (non-Javadoc)
	* @see com.meicheng.base.service.IDefaultService#getDataSource()
	*/
	public DataSource getDataSource() {
		return this.dataSource;
	}
	
	public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
		this.sqlSessionTemplate = sqlSessionTemplate;
	}
	
	/* (non-Javadoc)
	* @see com.meicheng.base.service.IDefaultService#getSqlSessionTemplate()
	*/
	@Override
	public SqlSessionTemplate getSqlSessionTemplate() {
		return this.sqlSessionTemplate;
	}
	
	public KeyUtil getKeyGenerator() {
		this.keyGenerator = new KeyUtil();
		return this.keyGenerator;
	}
	
	protected String getSql(String statement) {
		statement = this.getStatement(statement);
		String sql = this.getSqlSessionTemplate().getSqlSessionFactory().getConfiguration()
				.getMappedStatement(statement).getBoundSql(null).getSql();
		return sql;
	}
	
	protected String getStatement(String key) {
		String statement = null;
		if(null != key && !"".equals(key) && key.indexOf(".") != -1) {
			statement = key;
		} else {
			statement = this.getClass().getName() + "." + key;
		}
		return statement;
	}
	
	protected <T> void save(String statement, T t) {
		String statementId = this.getStatement(statement);
		this.getSqlSessionTemplate().insert(statementId, t);
	}
	
	protected <T> void update(String statement, T t) {
		String statementId = this.getStatement(statement);
		this.getSqlSessionTemplate().update(statementId, t);
	}
	
	protected <T> void save(T t) {
		String statementId = this.getStatement("save");
		this.save(statementId, t);
	}
	
	protected <T> void update(T t) {
		String statementId = this.getStatement("update");
		this.update(statementId, t);
	}
	
	protected <T extends ValueObject> void saveOrUpdate(T t) {
		if(null != t) {
			if(StringUtil.isEmpty(t.getCid())) {
				t.setCid(this.getKeyGenerator().getUUID());
				this.save(t);
			} else {
				this.update(t);
			}
		}
	}
	
	protected void batchInsert(String statement, List<?> list) {
		this.batchInsert(statement, list, FREQUENCY_SIZE);
	}
	
	protected void batchUpdate(String statement, List<?> list) {
		this.batchUpdate(statement, list, FREQUENCY_SIZE);
	}
	
	protected void batchInsert(String statement, List<?> list, int frequency) {
		String statementId = this.getStatement(statement);
		SqlSession session = this.openBatchSession();
		for(int i=0; i<list.size(); i++) {
			if(i>0 && (i % frequency) == 0) {
				session.flushStatements();
			}
			session.insert(statementId, list.get(i));
		}
		session.flushStatements();
		if(session != null) {
			session.close();
		}
	}
	
	protected void batchUpdate(String statement, List<?> list, int frequency) {
		String statementId = this.getStatement(statement);
		SqlSession session = this.openBatchSession();
		for(int i=0; i<list.size(); i++) {
			if(i>0 && (i % frequency) == 0) {
				session.flushStatements();
			}
			session.update(statementId, list.get(i));
		}
		session.flushStatements();
		if(session != null) {
			session.close();
		}
	}
	
	protected void batchUpdateAutoCommit(String statement, List<?> list) {
		this.batchUpdateAutoCommit(statement, list, FREQUENCY_SIZE);
	}
	
	protected void batchUpdateAutoCommit(String statement, List<?> list, int frequency) {
		String statementId = this.getStatement(statement);
		SqlSession session = this.openBatchSession(false);
		for(int i=0; i<list.size(); i++) {
			if(i>0 && (i % frequency) == 0) {
				session.flushStatements();
			}
			session.update(statementId, list.get(i));
		}
		session.flushStatements();
		session.commit();
		if(session != null) {
			session.close();
		}
	}
	
	private SqlSession openBatchSession() {
		SqlSessionFactory factory = this.getSqlSessionTemplate().getSqlSessionFactory();
		SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, true);
		return sqlSession;
	}
	
	private SqlSession openBatchSession(boolean autoCommit) {
		SqlSessionFactory factory = this.getSqlSessionTemplate().getSqlSessionFactory();
		SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, autoCommit);
		return sqlSession;
	}
	
	@SuppressWarnings("unchecked")
	protected <T> List<T> selectList(String statement, Object o, int page, int rows) {
		statement = this.getStatement(statement);
		List<T> list = new ArrayList<T>();
		if(page != 0 && rows != 0) {
			int offset = (page - 1 < 0) ? rows : (page - 1) * rows;
			RowBounds rowBounds = new RowBounds(offset, rows);
			list = (List<T>) this.getSqlSessionTemplate().selectList(statement, o, rowBounds);
		} else {
			list = (List<T>) this.getSqlSessionTemplate().selectList(statement, o);
		}
		return list;
	}

}
